<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../Universal.css">
</head>
<body>
    
    <div id="cnblogs_post_body" class="blogpost-body">
        <h2>多线程介绍</h2>
    <p>学习多线程之前，我们先要了解几个关于多线程有关的概念。<br>进程：进程指正在运行的程序。确切的来说，当一个程序进入内存运行，即变成一个进程，进程是处于运行过程中的程序，并且具有一定独立功能。</p>
    <p>线程：线程是进程中的一个执行单元，负责当前进程中程序的执行，一个进程中至少有一个线程。一个进程中是可以有多个线程的，这个应用程序也可以称之为多线程程序。</p>
    <p>简而言之：一个程序运行后至少有一个进程，一个进程中可以包含多个线程</p>
    <p>什么是多线程呢？即就是一个程序中有多个线程在同时执行。<br>通过下图来区别单线程程序与多线程程序的不同：<br>单线程程序：即，若有多个任务只能依次执行。当上一个任务执行结束后，下一个任务开始执行。如，去网吧上网，网吧只能让一个人上网，当这个人下机后，下一个人才能上网。<br>多线程程序：即，若有多个任务可以同时执行。如，去网吧上网，网吧能够让多个人同时上网。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720085632505-745008115.png" alt=""></p>
    <h2>程序运行原理</h2>
    <h3>分时调度</h3>
    <p>所有线程轮流使用 CPU 的使用权，平均分配每个线程占用 CPU 的时间。</p>
    <h3>抢占式调度</h3>
    <p>优先让优先级高的线程使用 CPU，如果线程的优先级相同，那么会随机选择一个(线程随机性)，Java使用的为抢占式调度。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720085828646-1859065370.png" alt=""></p>
    <p><strong>抢占式调度详解</strong></p>
    <p>大部分操作系统都支持多进程并发运行，现在的操作系统几乎都支持同时运行多个程序。比如：现在我们上课一边使用编辑器，一边使用录屏软件，同时还开着画图板，dos窗口等软件。此时，这些程序是在同时运行，”感觉这些软件好像在同一时刻运行着“。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720090551052-2007923019.png" alt=""></p>
    <p>实际上，CPU(中央处理器)使用抢占式调度模式在多个线程间进行着高速的切换。对于CPU的一个核而言，某个时刻，只能执行一个线程，而 CPU的在多个线程间切换速度相对我们的感觉要快，看上去就是在同一时刻运行。<br>其实，多线程程序并不能提高程序的运行速度，但能够提高程序运行效率，让CPU的使用率更高。</p>
    <h3>主线程</h3>
    <p>回想我们以前学习中写过的代码，当我们在dos命令行中输入java空格类名回车后，启动JVM，并且加载对应的class文件。虚拟机并会从main方法开始执行我们的程序代码，一直把main方法的代码执行结束。如果在执行过程遇到循环时间比较长的代码，那么在循环之后的其他代码是不会被马上执行的。如下代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Demo{
        String name;
        Demo(String name){
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
        }
        </span><span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> show()    {
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i=1;i&lt;=10000 ;i++<span style="color: rgba(0, 0, 0, 1)"> )    {
                System.out.println(</span>"name="+name+",i="+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }
    
    </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
            Demo d </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Demo("小强"<span style="color: rgba(0, 0, 0, 1)">);
            Demo d2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Demo("旺财"<span style="color: rgba(0, 0, 0, 1)">);
            d.show();
            d2.show();
            System.out.println(</span>"Hello World!"<span style="color: rgba(0, 0, 0, 1)">);
        }
    }</span></pre>
    </div>
    <p>若在上述代码中show方法中的循环执行次数很多，这时在d.show();下面的代码是不会马上执行的，并且在dos窗口会看到不停的输出name=小强,i=值，这样的语句。为什么会这样呢？</p>
    <p>原因是：jvm启动后，必然有一个执行路径(线程)从main方法开始的，一直执行到main方法结束，这个线程在java中称之为主线程。当程序的主线程执行时，如果遇到了循环而导致程序在指定位置停留时间过长，则无法马上执行下面的程序，需要等待循环结束后能够执行。那么，能否实现一个主线程负责执行其中一个循环，再由另一个线程负责其他代码的执行，最终实现多部分代码同时执行的效果？</p>
    <p>能够实现同时执行，通过Java中的多线程技术来解决该问题。</p>
    <h2>Thread类</h2>
    <p>该如何创建线程呢？通过API中搜索，查到Thread类。通过阅读Thread类中的描述。Thread是程序中的执行线程。Java 虚拟机允许应用程序并发地运行多个执行线程。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720090614021-709647078.png" alt=""></p>
    <p>构造方法</p>
    <p>&nbsp;<img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720090623615-1285946242.png" alt=""></p>
    <p>常用方法</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720090633302-2034637936.png" alt=""></p>
    <p>继续阅读，发现创建新执行线程有两种方法。</p>
    <ul>
    <li>一种方法是将类声明为 Thread 的子类。该子类应重写 Thread 类的 run 方法。创建对象，开启线程。run方法相当于其他线程的main方法。</li>
    <li>另一种方法是声明一个实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象，传入到某个线程的构造方法中，开启线程。</li>
    </ul>
    <h3>创建线程方式一继承Thread类</h3>
    <p>创建线程的步骤：</p>
    <ul>
    <li>1 定义一个类继承Thread。</li>
    <li>2 重写run方法。</li>
    <li>3 创建子类对象，就是创建线程对象。</li>
    <li>4 调用start方法，开启线程并让线程执行，同时还会告诉jvm去调用run方法。</li>
    </ul>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;<br>//测试类
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Demo01 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建自定义线程对象</span>
            MyThread mt = <span style="color: rgba(0, 0, 255, 1)">new</span> MyThread("新的线程！"<span style="color: rgba(0, 0, 0, 1)">);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开启新线程</span>
    <span style="color: rgba(0, 0, 0, 1)">        mt.start();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在主方法中执行for循环</span>
            <span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
                System.out.println(</span>"main线程！"+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }
    //线程类
     </span><span style="color: rgba(0, 0, 255, 1)">class</span> MyThread <span style="color: rgba(0, 0, 255, 1)">extends</span><span style="color: rgba(0, 0, 0, 1)"> Thread {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义指定线程名称的构造方法</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MyThread(String name) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用父类的String参数的构造方法，指定线程的名称</span>
            <span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(name);
        }
        </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)">
         * 重写run方法，完成该线程执行的逻辑
         </span><span style="color: rgba(0, 128, 0, 1)">*/</span><span style="color: rgba(0, 0, 0, 1)">
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
                System.out.println(getName()</span>+"：正在执行！"+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }</span></pre>
    </div>
    <p>线程对象调用 run方法和调用start方法区别？线程对象调用run方法不开启线程。仅是对象调用方法。线程对象调用start开启线程，并让jvm调用run方法在开启的线程中执行。</p>
    <h3>继承Thread类原理</h3>
    <p>我们为什么要继承Thread类，并调用其的start方法才能开启线程呢？<br>继承Thread类：因为Thread类用来描述线程，具备线程应该有功能。那为什么不直接创建Thread类的对象呢？如下代码：</p>
    <div class="cnblogs_code">
    <pre>Thread t1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread();
    t1.start();</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">这样做没有错，但是该start调用的是Thread类中的run方法，而这个run方法没有做什么事情，更重要的是这个run方法中并没有定义我们需要让线程执行的代码。</span></pre>
    </div>
    <p>创建线程的目的是什么？</p>
    <p>是为了建立程序单独的执行路径，让多部分代码实现同时执行。也就是说线程创建并执行需要给定线程要执行的任务。</p>
    <p>对于之前所讲的主线程，它的任务定义在main函数中。自定义线程需要执行的任务都定义在run方法中。</p>
    <p>Thread类run方法中的任务并不是我们所需要的，只有重写这个run方法。既然Thread类已经定义了线程任务的编写位置（run方法），那么只要在编写位置（run方法）中定义任务代码即可。所以进行了重写run方法动作。</p>
    <p>多线程的内存图解<br>多线程执行时，到底在内存中是如何运行的呢？以上个程序为例，进行图解说明：</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720091524458-2002544481.png" alt=""></p>
    <p>多线程执行时，在栈内存中，其实每一个执行线程都有一片自己所属的栈内存空间。进行方法的压栈和弹栈。当执行线程的任务结束了，线程自动在栈内存中释放了。但是当所有的执行线程都结束了，那么进程就结束了。</p>
    <h3>获取线程名称</h3>
    <p>开启的线程都会有自己的独立运行栈内存，那么这些运行的线程的名字是什么呢？该如何获取呢？既然是线程的名字，按照面向对象的特点，是哪个对象的属性和谁的功能，那么我们就去找那个对象就可以了。查阅Thread类的API文档发现有个方法是获取当前正在运行的线程对象。还有个方法是获取当前线程对象的名称。既然找到了，我们就可以试试。</p>
    <ul>
    <li>Thread.currentThread()获取当前线程对象</li>
    <li>Thread.currentThread().getName();获取当前线程对象的名称</li>
    
    
    
    
    
    
    
    
    </ul>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">class</span> MyThread <span style="color: rgba(0, 0, 255, 1)">extends</span> Thread { <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">继承Thread</span>
    <span style="color: rgba(0, 0, 0, 1)">    MyThread(String name){
            </span><span style="color: rgba(0, 0, 255, 1)">super</span><span style="color: rgba(0, 0, 0, 1)">(name);
        }
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">复写其中的run方法</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run(){
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i=1;i&lt;=20 ;i++<span style="color: rgba(0, 0, 0, 1)"> ){
                System.out.println(Thread.currentThread().getName()</span>+",i="+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建两个线程任务</span>
            MyThread d = <span style="color: rgba(0, 0, 255, 1)">new</span> MyThread("d"<span style="color: rgba(0, 0, 0, 1)">);
            MyThread d2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> MyThread("d2"<span style="color: rgba(0, 0, 0, 1)">);
            d.run();</span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">没有开启新线程, 在主线程调用run方法</span>
            d2.start();<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开启一个新线程，新线程调用run方法</span>
    <span style="color: rgba(0, 0, 0, 1)">    }
    }</span></pre>
    </div>
    <p>通过结果观察，原来主线程的名称：main；自定义的线程：Thread-1，线程多个时，数字顺延。如Thread-1......</p>
    <p>进行多线程编程时，不要忘记了Java程序运行是从主线程开始，main方法就是主线程的线程执行内容。</p>
    <h2>创建线程方式—实现Runnable接口</h2>
    <p>创建线程的另一种方法是声明实现 Runnable 接口的类。该类然后实现 run 方法。然后创建Runnable的子类对象，传入到某个线程的构造方法中，开启线程。<br>为何要实现Runnable接口，Runable是啥玩意呢？继续API搜索。<br>查看Runnable接口说明文档：Runnable接口用来指定每个线程要执行的任务。包含了一个 run 的无参数抽象方法，需要由接口实现类重写该方法。</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720092444224-2029278061.png" alt=""></p>
    <p>接口中的方法</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720092454599-1262820415.png" alt=""></p>
    <p>Thread类构造方法</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720092503396-1555380298.png" alt=""></p>
    <p>创建线程的步骤。</p>
    <ul>
    <li>1、定义类实现Runnable接口。</li>
    <li>2、覆盖接口中的run方法。。</li>
    <li>3、创建Thread类的对象</li>
    <li>4、将Runnable接口的子类对象作为参数传递给Thread类的构造函数。</li>
    <li>5、调用Thread类的start方法开启线程。</li>
    
    
    
    
    
    </ul>
    <p>代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Demo03 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建线程执行目标类对象</span>
            Runnable runn = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MyRunnable();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">将Runnable接口的子类对象作为参数传递给Thread类的构造函数</span>
            Thread thread = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(runn);
            Thread thread2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(runn);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">开启线程</span>
    <span style="color: rgba(0, 0, 0, 1)">        thread.start();
            thread2.start();
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
                System.out.println(</span>"main线程：正在执行！"+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自定义线程执行任务类</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> MyRunnable <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable{
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义线程要执行的run方法逻辑</span>
    <span style="color: rgba(0, 0, 0, 1)">    @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; 10; i++<span style="color: rgba(0, 0, 0, 1)">) {
                System.out.println(</span>"我的线程：正在执行！"+<span style="color: rgba(0, 0, 0, 1)">i);
            }
        }
    }</span></pre>
    </div>
    <h3>实现Runnable的原理</h3>
    <p>为什么需要定一个类去实现Runnable接口呢？继承Thread类和实现Runnable接口有啥区别呢？</p>
    <p>实现Runnable接口，避免了继承Thread类的单继承局限性。覆盖Runnable接口中的run方法，将线程任务代码定义到run方法中。</p>
    <p>创建Thread类的对象，只有创建Thread类的对象才可以创建线程。线程任务已被封装到Runnable接口的run方法中，而这个run方法所属于Runnable接口的子类对象，所以将这个子类对象作为参数传递给Thread的构造函数，这样，线程对象创建时就可以明确要运行的线程的任务。</p>
    <h3>实现Runnable的好处</h3>
    <p>第二种方式实现Runnable接口避免了单继承的局限性，所以较为常用。实现Runnable接口的方式，更加的符合面向对象，线程分为两部分，一部分线程对象，一部分线程任务。继承Thread类，线程对象和线程任务耦合在一起。一旦创建Thread类的子类对象，既是线程对象，又有线程任务。实现runnable接口，将线程任务单独分离出来封装成对象，类型就是Runnable接口类型。Runnable接口对线程对象和线程任务进行解耦。</p>
    <h3>线程的匿名内部类使用</h3>
    <p>使用线程的内匿名内部类方式，可以方便的实现每个线程执行不同的线程任务操作。<br>方式1：创建线程对象时，直接重写Thread类中的run方法</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Demo04 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span>  <span style="color: rgba(0, 0, 255, 1)">static</span>  <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)">  main(String[]args){
            </span><span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread() {
                </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
                    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> x = 0; x &lt; 40; x++<span style="color: rgba(0, 0, 0, 1)">) {
                        System.out.println(Thread.currentThread().getName()</span>+ "...X...." +<span style="color: rgba(0, 0, 0, 1)"> x);
                    }
                }
            }.start();
        }
    }</span></pre>
    </div>
    <p>方式2：使用匿名内部类的方式实现Runnable接口，重新Runnable接口中的run方法</p>
    <div class="cnblogs_code">
    <pre>      Runnable r = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Runnable() {
                </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
                    </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> x = 0; x &lt; 40; x++<span style="color: rgba(0, 0, 0, 1)">) {
                        System.out.println(Thread.currentThread().getName()
                                </span>+ "...Y...." +<span style="color: rgba(0, 0, 0, 1)"> x);
                    }
                }
            };
            </span><span style="color: rgba(0, 0, 255, 1)">new</span> Thread(r).start();</pre>
    </div>
    <h2>线程池</h2>
    <p>线程池，其实就是一个容纳多个线程的容器，其中的线程可以反复使用，省去了频繁创建线程对象的操作，无需反复创建线程而消耗过多资源。</p>
    <p>我们详细的解释一下为什么要使用线程池？</p>
    <p>在java中，如果每个请求到达就创建一个新线程，开销是相当大的。在实际使用中，创建和销毁线程花费的时间和消耗的系统资源都相当大，甚至可能要比在处理实际的用户请求的时间和资源要多的多。除了创建和销毁线程的开销之外，活动的线程也需要消耗系统资源。如果在一个jvm里创建太多的线程，可能会使系统由于过度消耗内存或“切换过度”而导致系统资源不足。为了防止资源不足，需要采取一些办法来限制任何给定时刻处理的请求数目，尽可能减少创建和销毁线程的次数，特别是一些资源耗费比较大的线程的创建和销毁，尽量利用已有对象来进行服务。</p>
    <p>线程池主要用来解决线程生命周期开销问题和资源不足问题。通过对多个任务重复使用线程，线程创建的开销就被分摊到了多个任务上了，而且由于在请求到达时线程已经存在，所以消除了线程创建所带来的延迟。这样，就可以立即为请求服务，使用应用程序响应更快。另外，通过适当的调整线程中的线程数目可以防止出现资源不足的情况。</p>
    <h3>使用线程池方式--Runnable接口</h3>
    <p>通常，线程池都是通过线程池工厂创建，再调用线程池中的方法获取线程，再通过线程去执行任务方法。 <br>Executors：线程池创建工厂类</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> ExecutorService newFixedThreadPool(<span style="color: rgba(0, 0, 255, 1)">int</span> nThreads)：返回线程池对象</pre>
    </div>
    <p>ExecutorService：线程池类</p>
    <div class="cnblogs_code">
    <pre>Future&lt;?&gt;<span style="color: rgba(0, 0, 0, 1)"> submit(Runnable task)：获取线程池中的某一个线程对象，并执行
    Future接口：用来记录线程任务执行完毕后产生的结果。线程池创建与使用</span></pre>
    </div>
    <p>使用线程池中线程对象的步骤：</p>
    <ul>
    <li>创建线程池对象</li>
    <li>创建Runnable接口子类对象</li>
    <li>提交Runnable接口子类对象</li>
    <li>关闭线程池</li>
    </ul>
    <p>代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.ExecutorService;
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.Executors;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadPoolDemo {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建线程池对象</span>
            ExecutorService service = Executors.newFixedThreadPool(2);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">包含2个线程对象
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建Runnable实例对象</span>
            MyRunnable r = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MyRunnable();
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">自己创建线程对象的方式
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Thread t = new Thread(r);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">t.start(); ---&gt; 调用MyRunnable中的run()
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从线程池中获取线程对象,然后调用MyRunnable中的run()</span>
    <span style="color: rgba(0, 0, 0, 1)">        service.submit(r);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">再获取个线程对象，调用MyRunnable中的run()</span>
    <span style="color: rgba(0, 0, 0, 1)">        service.submit(r);
            service.submit(r);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意：submit方法调用结束后，程序并不终止，是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">关闭线程池
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">service.shutdown();</span>
    <span style="color: rgba(0, 0, 0, 1)">    }
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Runnable接口实现类</span>
    <span style="color: rgba(0, 0, 255, 1)">class</span> MyRunnable <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            System.out.println(</span>"我要一个教练"<span style="color: rgba(0, 0, 0, 1)">);
    
            </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                Thread.sleep(</span>2000<span style="color: rgba(0, 0, 0, 1)">);
            } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(</span>"教练来了： " +<span style="color: rgba(0, 0, 0, 1)"> Thread.currentThread().getName());
            System.out.println(</span>"教我游泳,交完后，教练回到了游泳池"<span style="color: rgba(0, 0, 0, 1)">);
        }
    }</span></pre>
    </div>
    <h3>使用线程池方式—Callable接口</h3>
    <p>Callable接口：与Runnable接口功能相似，用来指定线程的任务。其中的call()方法，用来返回线程任务执行完毕后的结果，call方法可抛出异常。</p>
    <p>ExecutorService：线程池类</p>
    <div class="cnblogs_code">
    <pre>&lt;T&gt; Future&lt;T&gt; submit(Callable&lt;T&gt; task)：获取线程池中的某一个线程对象，并执行线程中的call()方法</pre>
    </div>
    <p>Future接口：用来记录线程任务执行完毕后产生的结果。线程池创建与使用</p>
    <ul>
    <li>使用线程池中线程对象的步骤：</li>
    <li>创建线程池对象</li>
    <li>创建Callable接口子类对象</li>
    <li>提交Callable接口子类对象</li>
    <li>关闭线程池</li>
    </ul>
    <p>代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.Callable;
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.ExecutorService;
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.concurrent.Executors;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadPoolDemo02 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建线程池对象</span>
            ExecutorService service = Executors.newFixedThreadPool(2);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">包含2个线程对象
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建Callable对象</span>
            MyCallable c = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> MyCallable();
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">从线程池中获取线程对象,然后调用MyRunnable中的run()</span>
    <span style="color: rgba(0, 0, 0, 1)">        service.submit(c);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">再获取个教练</span>
    <span style="color: rgba(0, 0, 0, 1)">        service.submit(c);
            service.submit(c);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">注意：submit方法调用结束后，程序并不终止，是因为线程池控制了线程的关闭。将使用完的线程又归还到了线程池中
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">关闭线程池
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">service.shutdown();</span>
    <span style="color: rgba(0, 0, 0, 1)">    }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Callable接口实现类,call方法可抛出异常、返回线程任务执行完毕后的结果</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> MyCallable <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Callable {
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> Object call() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
            System.out.println(</span>"我要一个教练:call"<span style="color: rgba(0, 0, 0, 1)">);
            Thread.sleep(</span>2000<span style="color: rgba(0, 0, 0, 1)">);
            System.out.println(</span>"教练来了： " +<span style="color: rgba(0, 0, 0, 1)">Thread.currentThread().getName());
            System.out.println(</span>"教我游泳,交完后,教练回到了游泳池"<span style="color: rgba(0, 0, 0, 1)">);
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> <span style="color: rgba(0, 0, 255, 1)">null</span><span style="color: rgba(0, 0, 0, 1)">;
        }
    }</span></pre>
    </div>
    <h3>线程池练习：返回两个数相加的结果</h3>
    <p>要求：通过线程池中的线程对象，使用Callable接口完成两个数求和操作</p>
    <ul>
    <li>Future接口：用来记录线程任务执行完毕后产生的结果。线程池创建与使用</li>
    <li>V get() 获取Future对象中封装的数据结果</li>
    </ul>
    <p>代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">import</span> java.util.concurrent.*<span style="color: rgba(0, 0, 0, 1)">;
    
    </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadPoolDemo04 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> InterruptedException, ExecutionException {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建线程池对象</span>
            ExecutorService threadPool = Executors.newFixedThreadPool(2<span style="color: rgba(0, 0, 0, 1)">);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建一个Callable接口子类对象
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">MyCallable c = new MyCallable();</span>
            MyCallable c = <span style="color: rgba(0, 0, 255, 1)">new</span> MyCallable(100, 200<span style="color: rgba(0, 0, 0, 1)">);
            MyCallable c2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> MyCallable(10, 20<span style="color: rgba(0, 0, 0, 1)">);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取线程池中的线程，调用Callable接口子类对象中的call()方法, 完成求和操作
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">&lt;Integer&gt; Future&lt;Integer&gt; submit(Callable&lt;Integer&gt; task)
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Future 结果对象</span>
            Future&lt;Integer&gt; result =<span style="color: rgba(0, 0, 0, 1)"> threadPool.submit(c);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">此 Future 的 get 方法所返回的结果类型</span>
            Integer sum =<span style="color: rgba(0, 0, 0, 1)"> result.get();
            System.out.println(</span>"sum=" +<span style="color: rgba(0, 0, 0, 1)"> sum);
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">再演示</span>
            result =<span style="color: rgba(0, 0, 0, 1)"> threadPool.submit(c2);
            sum </span>=<span style="color: rgba(0, 0, 0, 1)"> result.get();
            System.out.println(</span>"sum=" +<span style="color: rgba(0, 0, 0, 1)"> sum);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">关闭线程池(可以不关闭)</span>
    <span style="color: rgba(0, 0, 0, 1)">
        }
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Callable接口实现类</span>
    <span style="color: rgba(0, 0, 255, 1)">class</span> MyCallable <span style="color: rgba(0, 0, 255, 1)">implements</span> Callable&lt;Integer&gt;<span style="color: rgba(0, 0, 0, 1)"> {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">成员变量</span>
        <span style="color: rgba(0, 0, 255, 1)">int</span> x = 5<span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 0, 255, 1)">int</span> y = 3<span style="color: rgba(0, 0, 0, 1)">;
    
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">构造方法</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> MyCallable() {
        }
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> MyCallable(<span style="color: rgba(0, 0, 255, 1)">int</span> x, <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> y) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.x =<span style="color: rgba(0, 0, 0, 1)"> x;
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.y =<span style="color: rgba(0, 0, 0, 1)"> y;
        }
    
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> Integer call() <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> Exception {
            </span><span style="color: rgba(0, 0, 255, 1)">return</span> x +<span style="color: rgba(0, 0, 0, 1)"> y;
        }
    }</span></pre>
    </div>
    <h1>线程安全</h1>
    <p>如果有多个线程在同时运行，而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样的，而且其他的变量的值也和预期的是一样的，就是线程安全的。</p>
    <p>我们通过一个案例，演示线程的安全问题：</p>
    <p>电影院要卖票，我们模拟电影院的卖票过程。假设要播放的电影是 “功夫熊猫3”，本次电影的座位共100个(本场电影只能卖100张票)。</p>
    <p>我们来模拟电影院的售票窗口，实现多个窗口同时卖 “功夫熊猫3”这场电影票(多个窗口一起卖这100张票)</p>
    <p>需要窗口，采用线程对象来模拟；需要票，Runnable接口子类来模拟</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试类</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo05 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建票对象</span>
            Ticket ticket = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Ticket();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建3个窗口</span>
            Thread t1  = <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口1"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t2  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口2"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t3  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口3"<span style="color: rgba(0, 0, 0, 1)">);
            t1.start();
            t2.start();
            t3.start();
        }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟票</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> Ticket <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共100票</span>
        <span style="color: rgba(0, 0, 255, 1)">int</span> ticket = 100<span style="color: rgba(0, 0, 0, 1)">;
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟卖票</span>
            <span style="color: rgba(0, 0, 255, 1)">while</span>(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">){
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ticket &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟选坐的操作</span>
                    <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                        Thread.sleep(</span>1<span style="color: rgba(0, 0, 0, 1)">);
                    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() </span>+ "正在卖票:" + ticket--<span style="color: rgba(0, 0, 0, 1)">);
                }
            }
        }
    }</span></pre>
    </div>
    <p>运行结果发现：上面程序出现了问题</p>
    <ul>
    <li>票出现了重复的票</li>
    <li>错误的票 0、-1</li>
    </ul>
    <p>其实，线程安全问题都是由全局变量及静态变量引起的。若每个线程中对全局变量、静态变量只有读操作，而无写操作，一般来说，这个全局变量是线程安全的；若有多个线程同时执行写操作，一般都需要考虑线程同步，否则的话就可能影响线程安全。</p>
    <h2>线程同步（线程安全处理Synchronized）</h2>
    <p>java中提供了线程同步机制，它能够解决上述的线程安全问题。</p>
    <p>线程同步的方式有两种：</p>
    <ul>
    <li>方式1：同步代码块</li>
    <li>方式2：同步方法</li>
    </ul>
    <h3>同步代码块</h3>
    <p>同步代码块: 在代码块声明上 加上synchronized</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (锁对象) {
        可能会产生线程安全问题的代码
    }</span></pre>
    </div>
    <p>同步代码块中的锁对象可以是任意的对象；但多个线程时，要使用同一个锁对象才能够保证线程安全。</p>
    <p>使用同步代码块，对电影院卖票案例中Ticket类进行如下代码修改：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试类</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo05 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建票对象</span>
            Ticket ticket = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Ticket();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建3个窗口</span>
            Thread t1  = <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口1"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t2  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口2"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t3  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口3"<span style="color: rgba(0, 0, 0, 1)">);
            t1.start();
            t2.start();
            t3.start();
        }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟票</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> Ticket <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共100票</span>
        <span style="color: rgba(0, 0, 255, 1)">int</span> ticket = 100<span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义锁对象</span>
        Object lock = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟卖票</span>
            <span style="color: rgba(0, 0, 255, 1)">while</span>(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">){
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">同步代码块</span>
                <span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (lock){
                    </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ticket &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟电影选坐的操作</span>
                        <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                            Thread.sleep(</span>10<span style="color: rgba(0, 0, 0, 1)">);
                        } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println(Thread.currentThread().getName() </span>+ "正在卖票:" + ticket--<span style="color: rgba(0, 0, 0, 1)">);
                    }
                }
            }
        }
    }</span></pre>
    </div>
    <p>当使用了同步代码块后，上述的线程的安全问题，解决了。</p>
    <h3>同步方法</h3>
    <p>同步方法：在方法声明上加上synchronized</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">synchronized</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> method(){
           可能会产生线程安全问题的代码
    }</span></pre>
    </div>
    <p>同步方法中的锁对象是 this</p>
    <p>使用同步方法，对电影院卖票案例中Ticket类进行如下代码修改：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试类</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo05 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建票对象</span>
            Ticket ticket = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Ticket();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建3个窗口</span>
            Thread t1  = <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口1"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t2  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口2"<span style="color: rgba(0, 0, 0, 1)">);
            Thread t3  </span>= <span style="color: rgba(0, 0, 255, 1)">new</span> Thread(ticket, "窗口3"<span style="color: rgba(0, 0, 0, 1)">);
            t1.start();
            t2.start();
            t3.start();
        }
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟票</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> Ticket <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共100票</span>
        <span style="color: rgba(0, 0, 255, 1)">int</span> ticket = 100<span style="color: rgba(0, 0, 0, 1)">;
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义锁对象</span>
        Object lock = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟卖票</span>
            <span style="color: rgba(0, 0, 255, 1)">while</span>(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">){
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">同步方法</span>
    <span style="color: rgba(0, 0, 0, 1)">            method();
            }
        }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">同步方法,锁对象this</span>
        <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">synchronized</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> method(){
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ticket &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟选坐的操作</span>
                <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    Thread.sleep(</span>10<span style="color: rgba(0, 0, 0, 1)">);
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() </span>+ "正在卖票:" + ticket--<span style="color: rgba(0, 0, 0, 1)">);
            }
        }
    }</span></pre>
    </div>
    <h3>静态同步方法: 在方法声明上加上static synchronized</h3>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">synchronized</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> method(){
        可能会产生线程安全问题的代码
    }</span></pre>
    </div>
    <p>静态同步方法中的锁对象是 类名.class</p>
    <h1>死锁</h1>
    <p>同步锁使用的弊端：当线程任务中出现了多个同步(多个锁)时，如果同步中嵌套了其他的同步。这时容易引发一种现象：程序出现无限等待，这种现象我们称为死锁。这种情况能避免就避免掉。</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 0, 1)">synchronzied(A锁){
        </span><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)">(B锁){
        }
    }</span></pre>
    </div>
    <p>我们进行下死锁情况的代码演示：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 0, 255, 1)">import</span><span style="color: rgba(0, 0, 0, 1)"> java.util.Random;
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义锁对象类</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> MyLock {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Object lockA = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> Object lockB = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Object();
    }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">线程任务类</span>
     <span style="color: rgba(0, 0, 255, 1)">class</span> ThreadTask <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 0, 255, 1)">int</span> x = <span style="color: rgba(0, 0, 255, 1)">new</span> Random().nextInt(1);<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">0,1
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">指定线程要执行的任务代码</span>
    <span style="color: rgba(0, 0, 0, 1)">    @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 0, 255, 1)">while</span>(<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">){
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (x%2 ==0<span style="color: rgba(0, 0, 0, 1)">) {
                    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">情况一</span>
                    <span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (MyLock.lockA) {
                        System.out.println(</span>"if-LockA"<span style="color: rgba(0, 0, 0, 1)">);
                        </span><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (MyLock.lockB) {
                            System.out.println(</span>"if-LockB"<span style="color: rgba(0, 0, 0, 1)">);
                            System.out.println(</span>"if大口吃肉"<span style="color: rgba(0, 0, 0, 1)">);
                        }
                    }
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">情况二</span>
                    <span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (MyLock.lockB) {
                        System.out.println(</span>"else-LockB"<span style="color: rgba(0, 0, 0, 1)">);
                        </span><span style="color: rgba(0, 0, 255, 1)">synchronized</span><span style="color: rgba(0, 0, 0, 1)"> (MyLock.lockA) {
                            System.out.println(</span>"else-LockA"<span style="color: rgba(0, 0, 0, 1)">);
                            System.out.println(</span>"else大口吃肉"<span style="color: rgba(0, 0, 0, 1)">);
                        }
                    }
                }
                x</span>++<span style="color: rgba(0, 0, 0, 1)">;
            }
        }
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试类</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo06 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建线程任务类对象</span>
            ThreadTask task = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ThreadTask();
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建两个线程</span>
            Thread t1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(task);
            Thread t2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(task);
            </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">启动线程</span>
    <span style="color: rgba(0, 0, 0, 1)">        t1.start();
            t2.start();
        }
    }</span></pre>
    </div>
    <h3>Lock接口</h3>
    <p>查阅API，查阅Lock接口描述，Lock 实现提供了比使用 synchronized 方法和语句可获得的更广泛的锁定操作。</p>
    <p>Lock接口中的常用方法</p>
    <p><img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720100852708-2013580711.png" alt=""></p>
    <p>Lock提供了一个更加面对对象的锁，在该锁中提供了更多的操作锁的功能。</p>
    <p>我们使用Lock接口，以及其中的lock()方法和unlock()方法替代同步，对电影院卖票案例中Ticket类进行如下代码修改：</p>
    <div class="cnblogs_code">
    <pre> <span style="color: rgba(0, 0, 255, 1)">class</span> Ticket <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">共100票</span>
        <span style="color: rgba(0, 0, 255, 1)">int</span> ticket = 100<span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建Lock锁对象</span>
        Lock ck = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ReentrantLock();
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟卖票</span>
            <span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">synchronized (lock){</span>
    <span style="color: rgba(0, 0, 0, 1)">            ck.lock();
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (ticket &gt; 0<span style="color: rgba(0, 0, 0, 1)">) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟选坐的操作</span>
                    <span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                        Thread.sleep(</span>10<span style="color: rgba(0, 0, 0, 1)">);
                    } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() </span>+ "正在卖票:" + ticket--<span style="color: rgba(0, 0, 0, 1)">);
                }
                ck.unlock();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">}</span>
    <span style="color: rgba(0, 0, 0, 1)">        }
        }
    }</span></pre>
    </div>
    <h3>等待唤醒机制</h3>
    <p>在开始讲解等待唤醒机制之前，有必要搞清一个概念——线程之间的通信：多个线程在处理同一个资源，但是处理的动作（线程的任务）却不相同。通过一定的手段使各个线程能有效的利用资源。而这种手段即—— 等待唤醒机制。</p>
    <p>等待唤醒机制所涉及到的方法：</p>
    <ul>
    <li>wait（） :等待，将正在执行的线程释放其执行资格 和 执行权，并存储到线程池中。</li>
    <li>notify（）：唤醒，唤醒线程池中被wait（）的线程，一次唤醒一个，而且是任意的。</li>
    <li>notifyAll（）： 唤醒全部：可以将线程池中的所有wait() 线程都唤醒。</li>
    </ul>
    <p>其实，所谓唤醒的意思就是让 线程池中的线程具备执行资格。必须注意的是，这些方法都是在 同步中才有效。同时这些方法在使用时必须标明所属锁，这样才可以明确出这些方法操作的到底是哪个锁上的线程。</p>
    <p>仔细查看JavaAPI之后，发现这些方法 并不定义在 Thread中，也没定义在Runnable接口中，却被定义在了Object类中，为什么这些操作线程的方法定义在Object类中？</p>
    <p>因为这些方法在使用时，必须要标明所属的锁，而锁又可以是任意对象。能被任意对象调用的方法一定定义在Object类中。</p>
    <p>&nbsp;<img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720101329677-568282889.png" alt=""></p>
    <p>接下里，我们先从一个简单的示例入手:</p>
    <p>&nbsp;<img src="https://images2015.cnblogs.com/blog/612774/201707/612774-20170720101341568-1517728944.png" alt=""></p>
    <p>如上图说示，输入线程向Resource中输入name ,sex , 输出线程从资源中输出，先要完成的任务是：</p>
    <ul>
    <li>1.当input发现Resource中没有数据时，开始输入，输入完成后，叫output来输出。如果发现有数据，就wait();</li>
    <li>2.当output发现Resource中没有数据时，就wait() ；当发现有数据时，就输出，然后，叫醒input来输入数据。</li>
    </ul>
    <p>&nbsp;下面代码，模拟等待唤醒机制的实现：</p>
    <div class="cnblogs_code">
    <pre><span style="color: rgba(0, 0, 255, 1)">package</span><span style="color: rgba(0, 0, 0, 1)"> thread;
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">模拟资源类</span>
    <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> Resource {
        </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String name;
        </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String sex;
        </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">boolean</span> flag = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">synchronized</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> set(String name, String sex) {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span><span style="color: rgba(0, 0, 0, 1)"> (flag)
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    wait();
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                    e.printStackTrace();
                }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置成员变量</span>
            <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.sex =<span style="color: rgba(0, 0, 0, 1)"> sex;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 设置之后，Resource中有值，将标记该为 true ,</span>
            flag = <span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 唤醒output</span>
            <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.notify();
        }
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">synchronized</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> out() {
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> (!<span style="color: rgba(0, 0, 0, 1)">flag)
                </span><span style="color: rgba(0, 0, 255, 1)">try</span><span style="color: rgba(0, 0, 0, 1)"> {
                    wait();
                } </span><span style="color: rgba(0, 0, 255, 1)">catch</span><span style="color: rgba(0, 0, 0, 1)"> (InterruptedException e) {
                    e.printStackTrace();
                }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 输出线程将数据输出</span>
            System.out.println("姓名: " + name + "，性别: " +<span style="color: rgba(0, 0, 0, 1)"> sex);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 改变标记，以便输入线程输入数据</span>
            flag = <span style="color: rgba(0, 0, 255, 1)">false</span><span style="color: rgba(0, 0, 0, 1)">;
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 唤醒input，进行数据输入</span>
            <span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.notify();
        }
    }
    
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输入线程任务类</span>
    <span style="color: rgba(0, 0, 255, 1)">class</span> Input <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Resource r;
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Input(Resource r) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.r =<span style="color: rgba(0, 0, 0, 1)"> r;
        }
    
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 0, 255, 1)">int</span> count = 0<span style="color: rgba(0, 0, 0, 1)">;
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
                </span><span style="color: rgba(0, 0, 255, 1)">if</span> (count == 0<span style="color: rgba(0, 0, 0, 1)">) {
                    r.set(</span>"小明", "男生"<span style="color: rgba(0, 0, 0, 1)">);
                } </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)"> {
                    r.set(</span>"小花", "女生"<span style="color: rgba(0, 0, 0, 1)">);
                }
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 在两个数据之间进行切换</span>
                count = (count + 1) % 2<span style="color: rgba(0, 0, 0, 1)">;
            }
        }
    }
    
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">输出线程任务类</span>
    <span style="color: rgba(0, 0, 255, 1)">class</span> Output <span style="color: rgba(0, 0, 255, 1)">implements</span><span style="color: rgba(0, 0, 0, 1)"> Runnable {
        </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> Resource r;
    
        </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> Output(Resource r) {
            </span><span style="color: rgba(0, 0, 255, 1)">this</span>.r =<span style="color: rgba(0, 0, 0, 1)"> r;
        }
    
        @Override
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> run() {
            </span><span style="color: rgba(0, 0, 255, 1)">while</span> (<span style="color: rgba(0, 0, 255, 1)">true</span><span style="color: rgba(0, 0, 0, 1)">) {
                r.out();
            }
        }
    }
    
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">测试类</span>
    <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> ThreadDemo07 {
        </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) {
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 资源对象</span>
            Resource r = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Resource();
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 任务对象</span>
            Input in = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Input(r);
            Output out </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Output(r);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 线程对象</span>
            Thread t1 = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(in);
            Thread t2 </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Thread(out);
    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 开启线程</span>
    <span style="color: rgba(0, 0, 0, 1)">        t1.start();
            t2.start();
        }
    }</span></pre>
    </div>
    </div>

</body>
</html>